﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SHomeWorkshop.LunarConcept.Controls;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.Enums;
using System.Windows.Controls;
using System.Xml;
using System.Windows;
using SHomeWorkshop.LunarConcept.ModifingManager;
using System.Windows.Input;
using System.Windows.Media;

namespace SHomeWorkshop.LunarConcept.Widgets
{
    /// <summary>
    /// 创建时间：2012年1月2日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：作为线型部件的基类。这类部件的Canvas左上角的坐标固定在(0,0)，以便避免坐标换算。
    ///           线型部件，目前又分为ShapeWidget和ArrowLineWidget两大类。2012年6月8日
    /// </summary>
    public abstract class LineWidget : Widget
    {
        public LineWidget(PageEditor masterPageEditor)
            : base(masterPageEditor)
        {
            this.Child = this.mainCanvas;

            this.mainTextPanel.PreviewMouseLeftButtonDown +=
                new MouseButtonEventHandler(mainTextPanel_PreviewMouseLeftButtonDown);
            this.mainTextPanel.PreviewMouseLeftButtonUp +=
                new MouseButtonEventHandler(mainTextPanel_PreviewMouseLeftButtonUp);
            this.mainTextPanel.PreviewMouseRightButtonUp +=
                new MouseButtonEventHandler(mainTextPanel_PreviewMouseRightButtonUp);
        }

        protected LineDashType.DashType lineDash = LineDashType.DashType.Solid;
        [Tools.LunarProperty("LineDash", PropertyDateType.DashType)]
        public LineDashType.DashType LineDash
        {
            get { return lineDash; }
            set
            {
                lineDash = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("LineDash", lineDash.ToString());
                }

                RefreshLineDash();
            }
        }

        public virtual void RefreshLineDash()
        {

        }

        /// <summary>
        /// 线型部件，基板全部尺寸为零。这样可以在线外“穿透”选定。又不影响线的可视状态。
        /// </summary>
        protected Canvas mainCanvas = new Canvas()
        {
            Width = 0,
            Height = 0
        };

        public Canvas MainCanvas
        {
            get { return mainCanvas; }
        }

        /// <summary>
        /// [事实只读]对于LineWidget来说，此属性总是返回OutRect的左上角。
        /// 虽然可以给此属性赋值，但给此属性设置任何值都不会起任何作用。
        /// ——此属性是增添了新接口，为避免大幅度修改此前的代码才添加。2012年5月30日
        /// </summary>
        public Point Location
        {
            get { return TopLeft; }
            set { return; }
        }

        private static Thickness lineWidgetDefaultPadding = new Thickness(0);
        /// <summary>
        /// [读写]线型部件内间距总是０，其实无意义，只是为避免修改此前的一些代码才添加。2012年5月30日
        /// 给此属性设置任何值都不会起任何作用。
        /// 
        /// 2013年3月13日，令ArrowLineWidget支持内间距。
        /// </summary>
        public Thickness WidgetPadding
        {
            get { return lineWidgetDefaultPadding; }
            set { return; }
        }

        public override void Build()
        {
            base.Build();

            if (this.xmlData == null) return;

            //LineWidget类只需要读取WidgetStyle中的LineDash，但它不是任何与Style相关的属性的“最终实现”类。
            //因此，这里不调用任何Refreshxxx()方法。
        }

        protected override void BuildStyleProperties()
        {
            base.BuildStyleProperties();

            if (this.xmlData == null) return;

            WidgetStyle defStyleOfDoc;
            if (this.masterEditor != null && this.masterEditor.MasterManager != null)
            {
                defStyleOfDoc = this.masterEditor.MasterManager.GetDefaultWidgetStyle(this.WidgetClassName);
            }
            else
            {
                defStyleOfDoc = WidgetStyle.FromWidgetClassName(this.WidgetClassName);
            }

            //取线型。
            XmlAttribute attrLineDash = this.xmlData.GetAttribute(XmlTags.LineDashTag);
            if (attrLineDash != null)
            {
                lineDash = (LineDashType.DashType)Enum.Parse(typeof(LineDashType.DashType), attrLineDash.Value);
            }
            else
            {
                lineDash = defStyleOfDoc.LineDash;
            }
        }

        public override void BuildWidgetStylePropertiesAndRefresh()
        {
            base.BuildWidgetStylePropertiesAndRefresh();

            //此类不是任何Style Property的“最终实现类”。
            //因此此处不调用任何Refreshxxx()方法。
        }

        protected void mainTextPanel_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            ModifingItem<Action, ModifingInfo> mi = null;
            ModifingInfo info = null;
            if (FormatSelf(ref mi, ref info))
            {
                if (masterEditor != null)
                {
                    masterEditor.MouseInfo.DraggingType = Enums.PageDraggingType.MoveWidgets;
                }
                return;//格式刷格式化，不更改选定状态。
            }

            e.Handled = true;

            //双击则编辑。
            if (e.ClickCount == 2)
            {
                //防止误拖动部件。
                if (masterEditor != null && masterEditor.MasterManager != null)
                {
                    masterEditor.MouseInfo.DraggingType = masterEditor.MasterManager.MouseDraggingType;
                }

                this.SelectOnlySelf();

                if (Globals.MainWindow.IsPresentatingByPath == false)
                {
                    this.Edit();
                }
                return;
            }
            else
            {
                bool isShift = false;
                KeyStates ksRightShift = Keyboard.GetKeyStates(Key.RightShift);
                KeyStates ksLeftShift = Keyboard.GetKeyStates(Key.LeftShift);

                if ((ksRightShift & KeyStates.Down) > 0 || (ksLeftShift & KeyStates.Down) > 0) isShift = true;

                bool isCtrl = false;
                KeyStates ksRightCtrl = Keyboard.GetKeyStates(Key.RightCtrl);
                KeyStates ksLeftCtrl = Keyboard.GetKeyStates(Key.LeftCtrl);

                if ((ksRightCtrl & KeyStates.Down) > 0 || (ksLeftCtrl & KeyStates.Down) > 0) isCtrl = true;

                if (isShift || isCtrl)
                {
                    this.IsSelected = !this.IsSelected;

                    if (this.IsSelected) { this.IsMainSelected = true; }
                }
                else
                {
                    if (IsSelected == false)//如果没有选定，就先选定。如果已经选定，说明是要拖动。
                    {
                        SelectOnlySelf();
                    }
                }
            }

            //准备拖动。
            if (masterEditor != null)
            {
                masterEditor.MouseInfo.DraggingType = Enums.PageDraggingType.MoveWidgets;
                Point pt = e.GetPosition(this.masterEditor);
                pt = new Point(pt.X - this.masterEditor.BorderThickness.Left, pt.Y - this.masterEditor.BorderThickness.Top);
                masterEditor.MouseInfo.LeftButtonPreviewPoint = pt;
            }
        }

        protected void mainTextPanel_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //e.Handled = true;//会导致主界面无法及时刷新按钮【启用/禁用】状态。

            //2012年2月21日，将PageEditor的选定框改回使用装饰器来实现，结果意外发现：
            //保留下面这些代码会导致按Shift点击ContentWidget时可以实现多选ContentWidget，
            //——但一旦松开鼠标左键，立即会“只选定ContentWidget本身”！！！！
            //if (masterEditor != null)
            //{
            //    Point curPoint = e.GetPosition(masterEditor);
            //    if (Math.Abs(masterEditor.MouseInfo.LeftButtonPreviewPoint.X - curPoint.X) <= 4 &&
            //        Math.Abs(masterEditor.MouseInfo.LeftButtonPreviewPoint.Y - curPoint.Y) <= 4)
            //    {
            //        this.SelectOnlySelf();
            //    }
            //}
        }

        void mainTextPanel_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;

            if (this.IsSelected == false)
            {
                //如果未选定，就作为活动，
                this.SelectOnlySelf();
            }
            else
            {
                //若已选定，不更改选定范围，只更改“活动部件”为此部件
                if (this.IsMainSelected == false) this.IsMainSelected = true;
            }

            if (this.ContextMenu != null)
            {
                this.ContextMenu.IsOpen = true;
            }
        }

        /// <summary>
        /// 线型部件才需要。刷新坐标。
        /// </summary>
        public override void RefreshLocation()
        {
            RefreshTextPanelLocatin();
            this.RefreshCommentText();
            this.RefreshHyperLinkText();
        }

        public override Point BottomRight
        {
            get
            {
                return new Point(this.ActualWidth, this.ActualHeight);
            }
        }

        /// <summary>
        /// 按整数将源点的坐标给格式化一下。规则是四舍五入。
        /// </summary>
        /// <param name="pt">源点。</param>
        /// <returns>返回新坐标点。</returns>
        public Point FormatPoint(Point pt)
        {
            return new Point((int)(pt.X + 0.5), (int)(pt.Y + 0.5));
        }

        public abstract bool FormatSelf(ref ModifingItem<Action, ModifingInfo> mi, ref ModifingInfo info);

        public abstract void MoveWhenDraggingWidget(Point mousePoint);

        public abstract void DropWidget(ModifingItem<Action, ModifingInfo> mi, Point mousePoint);

        public abstract void UpdatePointsWhenPasting(Point basePasteTopLeft);

        /// <summary>
        /// 复制时取根据相对坐标更改后的各控制点坐标在内的Xml文本。粘贴功能所必须。
        /// </summary>
        /// <param name="relative"></param>
        /// <returns></returns>
        public abstract string GetRelativeOuterXml(Point baseCopyTopLeft);

        public abstract void RefreshPointWhenGroupIn(Point baseTopLeft);

        public abstract void RefreshPointWhenGroupOut(Point baseTopLeft);

        public abstract void MoveUp(ModifingItem<Action, ModifingInfo> mi, double units = 1);

        public abstract void MoveDown(ModifingItem<Action, ModifingInfo> mi, double units = 1);

        public abstract void MoveLeft(ModifingItem<Action, ModifingInfo> mi, double units = 1);

        public abstract void MoveRight(ModifingItem<Action, ModifingInfo> mi, double units = 1);

        public abstract void MoveWhenDraggingControler(Point newOutSidePoint);

        public abstract void DropWidgetControler(Point newMovingPoint, ModifingItem<Action, ModifingInfo> mi);

        public abstract void CollapseToTop(ModifingItem<Action, ModifingInfo> mi, double units = 1);

        public abstract void ExpandToBottom(ModifingItem<Action, ModifingInfo> mi, double units = 1);

        public abstract void CollapseToLeft(ModifingItem<Action, ModifingInfo> mi, double units = 1);

        public abstract void ExpandToRight(ModifingItem<Action, ModifingInfo> mi, double units = 1);

        public abstract void RefreshControlers();

        public override void RefreshIsSelected()
        {
            base.RefreshIsSelected();
            RefreshControlers();
        }
    }
}
